package com.atguigu.spring.ioc;

import com.atguigu.spring.ioc.bean.Dog;
import com.atguigu.spring.ioc.bean.Person;
import com.atguigu.spring.ioc.bean.SalaryDay;
import com.atguigu.spring.ioc.bean.User;
import com.atguigu.spring.ioc.controller.UserController;
import com.atguigu.spring.ioc.dao.UserDao;
import com.atguigu.spring.ioc.service.TAwareService;
import com.atguigu.spring.ioc.service.UserService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * 入口类
 */
@SpringBootApplication
public class Spring01IocApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext ioc = SpringApplication.run(Spring01IocApplication.class, args);
        System.out.println("===================ioc容器启动====================");

        User bean = ioc.getBean(User.class);
        System.out.println(bean);
    }

    public static void test3(String[] args) throws IOException {
        ConfigurableApplicationContext ioc = SpringApplication.run(Spring01IocApplication.class, args);
//        UserController bean = ioc.getBean(UserController.class);
//        System.out.println(bean);
        UserService userService = ioc.getBean(UserService.class);
        System.out.println("userService = " + userService);

        UserDao userDao = ioc.getBean(UserDao.class);
        System.out.println("userDao = " + userDao);

        TAwareService tawareService = ioc.getBean(TAwareService.class);
        System.out.println("tawareService = " + tawareService.getOSType() + tawareService.getBeanName());

        SalaryDay salaryDay = ioc.getBean(SalaryDay.class);
        System.out.println("salaryDay = " + salaryDay);

        // ResourceUtils用法
        File file = ResourceUtils.getFile("classpath:Avatar1.png");
        FileInputStream fis = new FileInputStream(file);
        int available = fis.available();
        System.out.println("available = " + available);
    }

    /**
     * Spring为我们提供了快速的MVC分层注解
     * 默认情况下,被分层注解的组件必须在XXXApplication类的包及其后代包中
     *
     * 1. @Controller 控制器
     * 2. @Service 服务层
     * 3. @Repository 持久层
     * 4. @Component 组件
     *
     * 第三方组件要导入容器时,无法修改第三方,加不了分层注解
     * 1. @Bean 在配置类中自己写个方法,new一个对象,方法加上@Bean
     * 2. 在Application类或组件类上用@Import(XXX.class)
     * @param args
     */
    public static void test2(String[] args) {
        ConfigurableApplicationContext ioc = SpringApplication.run(Spring01IocApplication.class, args);

//        UserController userContr = ioc.getBean(UserController.class);
//        System.out.println("bean = " + userContr);
        ConfigurableEnvironment env = ioc.getEnvironment();
        String property = env.getProperty("OS");
        System.out.println(property);

        ioc.getBeansOfType(Person.class).values().forEach(System.out::println);
        ioc.getBeansOfType(Dog.class).values().forEach(System.out::println);
    }

    /**
     * 组件，框架的底层配置
     *      配置文件：指定配置
     *      配置类：分类管理组件的配置
     * @param args String[]
     */
    public static void test1(String[] args) {
        // 1. 启动一个Spring应用      ApplicationContext： Spring应用上下文对象(IOC容器)
        ConfigurableApplicationContext run = SpringApplication.run(Spring01IocApplication.class, args);
        System.out.println(run);

        // 2. 容器中装了哪些组件的名字
//        for (String beanDefinitionName : run.getBeanDefinitionNames()) {
//            System.out.println(beanDefinitionName);
//        }

        // 4. 获取容器中的组件对象:精确获取某个组件
        // 组件的三大特性:名字、类型、对象、作用域
        System.out.println("=========================");

        // beans.factory.NoSuchBeanDefinitionException：组件不存在异常
        // beans.factory.NoUniqueBeanDefinitionException: 组件按照类型不唯一,按照类型只取一个异常
        // 4.1 按照组件名字获取对象
//        Person obj = (Person) run.getBean("what'sup");
//        System.out.println(obj);

        // 4.2 按照组件类型获取对象
//        Person obj2 = run.getBean(Person.class);
//        System.out.println(obj2);

        // 4.3 按照组件类型获取所有对象
//        Map<String, Person> beans = run.getBeansOfType(Person.class);
//        beans.forEach((k, v) -> {
//            System.out.println(v);
//        });

        // 4.4 按照类型+名字
        Person person = run.getBean("dogdan", Person.class);
        System.out.println(person);

        // 5. 组件是单实例的
        // 所有组件默认是单例的, 每次获取直接从容器中拿, 容器提前会创建
        System.out.println("=========================");
        Dog dog = run.getBean("dog1", Dog.class);
        System.out.println(dog);

        System.out.println("=========================");
        Dog dog2 = run.getBean("dog1", Dog.class);
        System.out.println(dog2);
        System.out.println("========================");
        Dog dog3 = run.getBean("dog2", Dog.class);
        System.out.println(dog3);
    }


}
